package com.hpq.user.service.impl;

import com.hpq.common.annotation.RedissonLock;
import com.hpq.common.domain.enums.IdempotentEnum;
import com.hpq.common.domain.enums.YesOrNoEnum;
import com.hpq.common.service.LockService;
import com.hpq.user.dao.UserBackpackDAO;
import com.hpq.user.domain.model.UserBackpack;
import com.hpq.user.service.UserBackpackService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.Objects;

/**
 * 物品发放幂等设计
 */
@Service
public class UserBackpackServiceImpl implements UserBackpackService {
    @Autowired
    private LockService lockService;
    @Autowired
    private UserBackpackDAO userBackpackDao;
    @Autowired
    @Lazy
    private UserBackpackServiceImpl  userBackpackService;
    /**
     * 给用户发放物品
     * @param id            用户id
     * @param itemId        物品id
     * @param idempotentEnum    幂等类型
     * @param businessId    幂等唯一性标识
     *
     * 分布式锁确保了同一时间只有一个请求能够执行关键业务逻辑，
     * 而幂等性确保了即使客户端发送了多次请求，服务器也只会处理一次。
     */
    @Override
    public void acquireItem(Long id, Long itemId, IdempotentEnum idempotentEnum, String businessId) {
        //获得幂等号
        String idempotent = getIdempotent(itemId,idempotentEnum,businessId);
        userBackpackService.doAcquire(id,itemId,idempotent);
    }
    //添加分布式锁
    @RedissonLock(key = "#idempotent",waitTime = 5000)
    public void doAcquire(Long id ,Long itemId,String idempotent){

            UserBackpack userBackpack = userBackpackDao.getByIdempotent(idempotent);
            if(Objects.nonNull(userBackpack)){
                return;
            }
            //发放物品
            UserBackpack insert = UserBackpack.builder()
                    .uid(id)
                    .itemId(itemId)
                    .status(YesOrNoEnum.NO.getStatus())
                    .idempotent(idempotent)
                    .build();
            userBackpackDao.save(insert);
    }
    private String getIdempotent(Long itemId, IdempotentEnum idempotentEnum, String businessId) {
        return String.format("%d_%d_%s",itemId,idempotentEnum.getType(),businessId);
    }
}
